package com.duojuhe.coremodule.system.service.impl;

import com.duojuhe.cache.LoginUserTokenCache;
import com.duojuhe.cache.SystemDictCache;
import com.duojuhe.common.annotation.DataScopeFilter;
import com.duojuhe.common.bean.UserTokenInfoVo;
import com.duojuhe.common.constant.DataScopeConstants;
import com.duojuhe.common.enums.SystemEnum;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.PageResult;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.utils.idgenerator.UUIDUtils;
import com.duojuhe.common.utils.page.PageHelperUtil;
import com.duojuhe.coremodule.BaseService;
import com.duojuhe.coremodule.system.entity.*;
import com.duojuhe.coremodule.system.mapper.*;
import com.duojuhe.coremodule.system.pojo.dto.role.*;
import com.duojuhe.coremodule.system.service.SystemRoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
public class SystemRoleServiceImpl extends BaseService implements SystemRoleService {
    @Resource
    private LoginUserTokenCache loginUserTokenCache;
    @Resource
    private SystemDictCache systemDictCache;
    @Resource
    private SystemRoleMapper systemRoleMapper;
    @Resource
    private SystemUserMapper systemUserMapper;
    @Resource
    private SystemMenuMapper systemMenuMapper;
    @Resource
    private SystemDeptMapper systemDeptMapper;
    @Resource
    private SystemRoleMenuMapper systemRoleMenuMapper;
    @Resource
    private SystemRoleDeptMapper systemRoleDeptMapper;

    /**
     * 【分页查询】分页查询角色list
     * @param req
     * @return
     */
    @Override
    @DataScopeFilter
    public ServiceResult<PageResult<List<QuerySystemRolePageRes>>> querySystemRolePageResList(QuerySystemRolePageReq req) {
        PageHelperUtil.orderByAndStartPage(req, "sort desc,createTime desc, roleId desc");
        List<QuerySystemRolePageRes> list = systemRoleMapper.querySystemRolePageResList(req);
        list.forEach(this::setHandleSystemRoleDictNameColor);
        return PageHelperUtil.returnServiceResult(req,list);
    }

    /**
     * 【下拉选择使用-查询所有角色】查询可供前端选择使用的角色，一般用于用户添加下拉选择使用
     * @param req
     * @return
     */
    @Override
    @DataScopeFilter(dataScope = DataScopeConstants.TENANT_ALL_DATA)
    public ServiceResult<List<SelectSystemRoleRes>> queryNormalSelectSystemRoleResList(SelectSystemRoleReq req) {
        PageHelperUtil.defaultOrderBy("sort desc,createTime desc,roleId desc");
        return ServiceResult.ok(systemRoleMapper.querySelectSystemRoleResListByStatusCode(req,SystemEnum.STATUS.NORMAL.getKey()));
    }

    /**
     * 【根据ID查询详情】根据角色ID查询角色详情
     * @param req
     * @return
     */
    @Override
    public ServiceResult<QuerySystemRoleRes> querySystemRoleResByRoleId(SystemRoleIdReq req) {
        QuerySystemRoleRes res = systemRoleMapper.querySystemRoleResByRoleId(req.getRoleId());
        setHandleSystemRoleDictNameColor(res);
        return ServiceResult.ok(res);
    }

    /**
     * 【保存】角色信息
     * @param req
     * @return
     */
    @Override
    public ServiceResult saveSystemRole(SaveSystemRoleReq req) {
        //当前登录人人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //当前时间
        Date date = new Date();
        //角色id
        String roleId = UUIDUtils.getUUID32();
        //构建角色对象
        SystemRole systemRole = new SystemRole();
        systemRole.setRoleId(roleId);
        systemRole.setRoleName(req.getRoleName());
        systemRole.setCreateTime(date);
        systemRole.setUpdateTime(date);
        systemRole.setCreateUserId(userTokenInfoVo.getUserId());
        systemRole.setUpdateUserId(userTokenInfoVo.getUserId());
        systemRole.setTenantId(userTokenInfoVo.getTenantId());
        systemRole.setCreateDeptId(userTokenInfoVo.getCreateDeptId());
        systemRole.setRemark(req.getRemark());
        systemRole.setSort(req.getSort());
        systemRole.setStatusCode(req.getStatusCode());
        systemRole.setDataScopeCode(DataScopeConstants.SELF_DATA);
        systemRoleMapper.insertSelective(systemRole);
        return ServiceResult.ok(roleId);
    }

    /**
     * 【修改】角色信息
     * @param req
     * @return
     */
    @Override
    public ServiceResult updateSystemRole(UpdateSystemRoleReq req) {
        //角色id
        String roleId = req.getRoleId();
        //查询对象
        SystemRole systemRoleOld = systemRoleMapper.selectByPrimaryKey(roleId);
        if (systemRoleOld == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //启用
        String normal = SystemEnum.STATUS.NORMAL.getKey();
        //禁用
        String forbid = SystemEnum.STATUS.FORBID.getKey();
        //如果原来是启用的并且改成禁用的  则需要判断该角色有没有被使用
        if (normal.equals(systemRoleOld.getStatusCode())&& forbid.equals(req.getStatusCode())) {
            //判断角色是否使用中，禁止删除
            checkSystemUserChildrenByRoleId(roleId,ErrorCodes.ROLE_IS_USE_CANNOT_FORBID);
        }
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        SystemRole systemRole = new SystemRole();
        systemRole.setRoleId(roleId);
        systemRole.setRoleName(req.getRoleName());
        systemRole.setUpdateTime(new Date());
        systemRole.setUpdateUserId(userTokenInfoVo.getUserId());
        systemRole.setRemark(req.getRemark());
        systemRole.setSort(req.getSort());
        systemRole.setStatusCode(req.getStatusCode());
        systemRoleMapper.updateByPrimaryKeySelective(systemRole);
        return ServiceResult.ok(roleId);
    }

    /**
     * 【删除】根据角色ID删除角色，注意一次仅能删除一个角色，存在绑定关系的则不能删除
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult deleteSystemRoleByRoleId(SystemRoleIdReq req) {
        String roleId = req.getRoleId();
        SystemRole systemRole = systemRoleMapper.selectByPrimaryKey(roleId);
        if (systemRole == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //判断角色是否使用中，禁止删除
        checkSystemUserChildrenByRoleId(roleId,ErrorCodes.ROLE_RELATION_USER_NOT_DELETE);
        //删除角色
        systemRoleMapper.deleteByPrimaryKey(roleId);
        //清空功能权限
        deleteSystemRoleMenuByRoleId(roleId);
        //清空数据权限
        deleteSystemRoleDeptByRoleId(roleId);
        return ServiceResult.ok(roleId);
    }

    /**
     * 【角色授权】给角色赋权限，menuIdList为空表示清除该角色所有权限
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult saveRoleAuthorization(SaveRoleAuthorizationReq req) {
        //角色id
        String roleId = req.getRoleId();
        SystemRole systemRoleOld = systemRoleMapper.selectByPrimaryKey(roleId);
        if (systemRoleOld == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //租户id
        String tenantId = systemRoleOld.getTenantId();
        if (StringUtils.isBlank(tenantId)){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //数据权限范围
        SystemRole systemRole = new SystemRole();
        systemRole.setRoleId(systemRoleOld.getRoleId());
        systemRole.setDataScopeCode(req.getDataScopeCode());
        systemRoleMapper.updateByPrimaryKeySelective(systemRole);
        //功能权限
        batchInsertSystemRoleMenuList(roleId,tenantId,req.getMenuIdList());
        //数据权限
        batchInsertSystemRoleDeptList(roleId,tenantId,req.getDataScopeCode(),req.getDeptIdList());
        //用户角色授权改变了，强制踢出所有该角色的的所有在线会话
        loginUserTokenCache.kickOutOnlineUserByRoleId(roleId);
        return ServiceResult.ok(roleId);
    }

    /**
     * 【角色绑定菜单-渲染角色绑定菜单】查询roleId对应的菜单权限集合，一般用于角色功能授权编辑时渲染已经用于的权限勾选
     * @param req
     * @return
     */
    @Override
    public ServiceResult<List<String>> querySystemMenuIdListByRoleId(SystemRoleIdReq req) {
        String roleId = req.getRoleId();
        SystemRole systemRole = systemRoleMapper.selectByPrimaryKey(roleId);
        if (systemRole == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        return ServiceResult.ok(systemRoleMenuMapper.querySystemMenuIdListByRoleId(roleId));
    }

    /**
     * 【角色绑定部门-渲染角色绑定部门】查询roleId对应的部门ID权限集合，一般用于角色数据授权编辑时渲染已经用于的权限勾选
     * @param req
     * @return
     */
    @Override
    public ServiceResult<List<String>> querySystemDeptIdListByRoleId(SystemRoleIdReq req) {
        String roleId = req.getRoleId();
        SystemRole systemRole = systemRoleMapper.selectByPrimaryKey(roleId);
        if (systemRole == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        return ServiceResult.ok(systemRoleDeptMapper.querySystemDeptIdListByRoleId(roleId));
    }



    /*====================================私有方法beg================================================**/
    /**
     * 【私有方法，辅助其他接口方法使用】 查找该节点下面是否存在子节点
     */
    private void checkSystemUserChildrenByRoleId(String roleId,ErrorCodes errorCodes) {
        if (StringUtils.isBlank(roleId)){
            throw new DuoJuHeException(errorCodes);
        }
        Example example = new Example(SystemUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("roleId", roleId);
        if (systemUserMapper.selectByExample(example).size() > 0) {
            throw new DuoJuHeException(errorCodes);
        }
    }


    /**
     * 批量插入功能菜单授权
     * @param roleId
     * @param menuIdList
     */
    private void batchInsertSystemRoleMenuList(String roleId,String tenantId,List<String> menuIdList){
        //清空功能权限
        deleteSystemRoleMenuByRoleId(roleId);
        if (StringUtils.isBlank(roleId) || menuIdList==null){
            return;
        }
        //判断传过来的菜单Id是否真实有效
        //根据集合查询有效的Id
        List<String> menuIds = systemMenuMapper.queryMenuIdListBySystemMenuIdList(menuIdList);
        if (menuIds == null || menuIds.size() == 0) {
            return;
        }
        //组装实体类集合
        //批量插入菜单ids
        List<SystemRoleMenu> systemRoleMenuList = new ArrayList<SystemRoleMenu>();
        for (String menuId : menuIds) {
            SystemRoleMenu roleMenu = new SystemRoleMenu();
            roleMenu.setId(UUIDUtils.getUUID32());
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(menuId);
            roleMenu.setTenantId(tenantId);
            systemRoleMenuList.add(roleMenu);
        }
        //插入新的权限
        systemRoleMenuMapper.batchInsertListUseAllCols(systemRoleMenuList);
    }

    /**
     * 批量插入数据权限授权
     * @param roleId
     * @param systemDeptIdList
     */
    private void batchInsertSystemRoleDeptList(String roleId,String tenantId,String dataScopeCode,List<String> systemDeptIdList){
        //清空数据权限
        deleteSystemRoleDeptByRoleId(roleId);
        if (StringUtils.isBlank(roleId) || systemDeptIdList==null
                || !DataScopeConstants.CUSTOM_DATA.equals(dataScopeCode)){
            return;
        }
        //根据集合查询有效的Id
        List<SystemDept> deptList = systemDeptMapper.queryDeptListBySystemDeptIdList(systemDeptIdList);
        if (deptList == null || deptList.size() == 0) {
            return;
        }
        //组装实体类集合
        //批量插入部门ids
        List<SystemRoleDept> systemRoleDeptList = new ArrayList<SystemRoleDept>();
        for (SystemDept dept : deptList) {
            SystemRoleDept roleDept = new SystemRoleDept();
            roleDept.setId(UUIDUtils.getUUID32());
            roleDept.setRoleId(roleId);
            roleDept.setDeptId(dept.getDeptId());
            roleDept.setTenantId(tenantId);
            systemRoleDeptList.add(roleDept);
        }
        //插入新的权限
        systemRoleDeptMapper.batchInsertListUseAllCols(systemRoleDeptList);
    }

    /**
     * 根据角色Id删除角色绑定菜单关系
     */
    private void deleteSystemRoleMenuByRoleId(String roleId) {
        if (StringUtils.isBlank(roleId)){
            return;
        }
        SystemRoleMenu roleMenu = new SystemRoleMenu();
        roleMenu.setRoleId(roleId);
        systemRoleMenuMapper.delete(roleMenu);
    }

    /**
     * 根据角色Id删除角色绑定部门绑定关系
     */
    private void deleteSystemRoleDeptByRoleId(String roleId) {
        if (StringUtils.isBlank(roleId)){
            return;
        }
        SystemRoleDept roleDept = new SystemRoleDept();
        roleDept.setRoleId(roleId);
        systemRoleDeptMapper.delete(roleDept);
    }


    /**
     * 处理返回值的数据字典
     * @param res
     */
    private void setHandleSystemRoleDictNameColor(HandleSystemRoleDictNameColorRes res) {
        if (res==null){
            return;
        }
        SystemDict dictStatus = systemDictCache.getSystemDictByDictCode(res.getStatusCode());
        res.setStatusName(dictStatus.getDictName());
        res.setStatusColor(dictStatus.getDictColor());

        SystemDict dictDataScope = systemDictCache.getSystemDictByDictCode(res.getDataScopeCode());
        res.setDataScopeName(dictDataScope.getDictName());
        res.setDataScopeColor(dictDataScope.getDictColor());
    }
    /*====================================私有方法end================================================**/
}
